package com.syf.kit.core.dao.sql.parse;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 动态转换，例如将  sql:  select * from tableName where col1=#{param1} and col2=#{param2}
 * 转换为 select * from tableName where col1=? and col2=?.
 */
public class GenericSqlConverter {
    /**
     * 转换开始标志
     */
    private String openToken;

    /**
     * 转换结束标志
     */
    private String closeToken;

    /**
     * 转换后，得出的参数名称列表
     */
    private List<String> paramNameList;

    public GenericSqlConverter(String openToken, String closeToken) {
        this.openToken = openToken;
        this.closeToken = closeToken;
        paramNameList = new ArrayList<String>(8);
    }

    public List<String> getParamNameList() {
        return this.paramNameList;
    }

    public String parse(String sql, Map<String, Object> paramMap) {
        if (sql == null || "".equals(sql)) {
            throw new NullPointerException("SQL是空字符串");
        }
        StringBuilder builder = new StringBuilder();
        StringBuilder expression = new StringBuilder();
        int paramKeySeq = 0;
        char[] src = sql.toCharArray();
        int offset = 0;
        int start = sql.indexOf(this.openToken, offset);
        while (start > -1) {
            if (start > 0 && src[start - 1] == '\\') {
                builder.append(src, offset, start - offset - 1).append(this.openToken);
                offset = start + this.openToken.length();
            } else {
                expression.setLength(0);
                builder.append(src, offset, start - offset);
                offset = start + this.openToken.length();
                int end = sql.indexOf(this.closeToken, offset);
                while (end > -1) {
                    if (end > offset && src[end - 1] == '\\') {
                        expression.append(src, offset, end - offset - 1).append(this.closeToken);
                        offset = end + this.closeToken.length();
                        end = sql.indexOf(this.closeToken, offset);
                        continue;
                    }
                    expression.append(src, offset, end - offset);
                    offset = end + this.closeToken.length();
                    break;
                }
                if (end == -1) {
                    builder.append(src, start, src.length - start);
                    offset = src.length;
                } else {
                    builder.append("?");
                    this.paramNameList.add(paramKeySeq, paramMap.get(expression.toString()) == null ? null : paramMap.get(expression.toString()).toString());
                    paramKeySeq++;
                    offset = end + this.closeToken.length();
                }
            }
            start = sql.indexOf(this.openToken, offset);
        }
        if (offset < src.length) {
            builder.append(src, offset, src.length - offset);
        }

        return builder.toString();
    }
}
